package ml;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;

public class MLSimulator {

	/**
	 * @param args1
	 *            data file name
	 * @param args2
	 *            skip lines
	 * @param args3
	 *            max read lines
	 */
	public static void main(String[] args) {
		if (args.length != 7) {
			System.err.println("Parameters are invalid.");
			System.exit(-1);
		}

		System.out.println("Start loading samples ...");
		SampleDataReader sampleLoader = new SampleDataReader(args[0]);
		ArrayList<Double> prices = sampleLoader.get_prices();
		System.out.println("Samples number: " + prices.size());
		System.out.println("Finished loading samples!\n");

		System.out.println("Start calculating labels ...");
		LabelMaker labelMaker = new LabelMaker(MLConstants.TIME_INTERVAL, MLConstants.MIN_PROFIT, MLConstants.MAX_LOSS);
		
		int label_num = prices.size() - MLConstants.TIME_INTERVAL;
		ArrayList<Boolean> rise_labels = labelMaker.calculate(prices, 0, label_num, false);
		ArrayList<Boolean> drop_labels = labelMaker.calculate(prices, 0, label_num, true);
		System.out.println("Finished calculating labels!\n");

		System.out.println("Statistics of RISE situation!");
		countLabels(rise_labels);
		System.out.println("Statistics of DROP situation!");
		countLabels(drop_labels);

		System.out.println("Start generating training samples ...");
		ArrayList<SampleData> usefulSamples = new ArrayList<SampleData>(label_num);
		for (int i = 0; i < label_num; ++i) {
			usefulSamples.add(sampleLoader.get_samples().get(i));
		}

		TrainSampleMaker rise_trainSampleMaker = new TrainSampleMaker(usefulSamples, rise_labels, true, MLConstants.TRAINING_GROUP_LEN,
						MLConstants.TRAINING_SAMPLES_RATE, Integer.valueOf(args[2]), Integer.valueOf(args[3]),
						MLConstants.TRAIN_INTERVAL);
		TrainSampleMaker drop_trainSampleMaker = new TrainSampleMaker(usefulSamples, drop_labels, false, MLConstants.TRAINING_GROUP_LEN,
						MLConstants.TRAINING_SAMPLES_RATE, Integer.valueOf(args[2]), Integer.valueOf(args[3]),
						MLConstants.TRAIN_INTERVAL);
		System.out.println("Finished generating training samples!\n");

		StrongClassifer rise_strongClassifier = null;
		StrongClassifer drop_strongClassifier = null;

		System.out.println("Start online training ...");

		Trading trading = new Trading(MLConstants.INI_ASSET, MLConstants.DECISION_TIME, MLConstants.DECISION_RATE,
						MLConstants.MIN_STOP_LOSS, MLConstants.TAKE_PROFIT, MLConstants.MIN_LEVERAGE);
		
		ArrayList<Double> all_test_prices = new ArrayList<Double>();
		ArrayList<Double> test_prices = new ArrayList<Double>();
		ArrayList<Boolean> cal_rise_labels = new ArrayList<Boolean>();
		ArrayList<Boolean> cal_drop_labels = new ArrayList<Boolean>();

		ArrayList<SampleData> train_samples = new ArrayList<SampleData>();
		ArrayList<Boolean> train_labels = new ArrayList<Boolean>();
		ArrayList<SampleData> test_samples = new ArrayList<SampleData>();
		ArrayList<Boolean> test_labels = new ArrayList<Boolean>();
		int cycles = 0;
		while (rise_trainSampleMaker.GetNext(train_samples, train_labels, test_samples, test_labels) == 0) {
			System.out.println("Training element: " + cycles);
			cycles += MLConstants.TRAIN_INTERVAL;
			rise_strongClassifier = AdaBoostTrainer.train(train_samples, train_labels, MLConstants.TRAINING_CYCLES);
			drop_trainSampleMaker.GetNext(train_samples, train_labels, test_samples, test_labels);
			drop_strongClassifier = AdaBoostTrainer.train(train_samples, train_labels, MLConstants.TRAINING_CYCLES);
			test_prices.clear();
			cal_rise_labels.clear();
			cal_drop_labels.clear();
			for (SampleData aSample : test_samples) {
				test_prices.add(aSample.get_price());
				all_test_prices.add(aSample.get_price());
				cal_rise_labels.add(rise_strongClassifier.judge(aSample.get_feature()));
				cal_drop_labels.add(drop_strongClassifier.judge(aSample.get_feature()));
			}
			
			trading.Update(test_prices, cal_rise_labels, cal_drop_labels, false);
			DumpTradingResults(trading, all_test_prices, args[4]);
		}
		trading.UpdateAtEnd(test_prices.get(test_prices.size()-1));

		System.out.println("Finished online training!\n");
	}

	private static void DumpTradingResults(Trading trading, ArrayList<Double> test_prices, String file_name) {
		ArrayList<Double> assets = trading.get_assets();
		ArrayList<Double> buy_vols = trading.get_buy_vols();
		ArrayList<Double> sell_vols = trading.get_sell_vols();
		try {
			BufferedWriter bw = new BufferedWriter(new FileWriter(file_name));
			util.DataUtil.OutputArray(bw, assets, 0, assets.size());
			util.DataUtil.OutputArray(bw, buy_vols, 0, assets.size());
			util.DataUtil.OutputArray(bw, sell_vols, 0, assets.size());
			util.DataUtil.OutputArray(bw, test_prices, 0, assets.size());
			bw.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private static void countLabels(ArrayList<Boolean> labels) {
		int pos = 0;
		int neg = 0;
		for (Boolean element : labels) {
			if (element) {
				++pos;
			} else {
				++neg;
			}
		}

		System.out.println("Positive labels:\t" + pos);
		System.out.println("Negtive labels:\t" + neg);
		System.out.println("All labels number:\t" + labels.size());
	}
}
